package edu.ncsu.csc.ip.routing.ls;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Comparator;

/**
 * Class <code>link_state</code>
 * 
 * Runs LinkState to comply with project 3 description
 * 
 * @author Moin Ayazifar <mayazif@ncsu.edu>
 * @author Steven Elliott <sdelliot@ncsu.edu>
 * 
 */

public class all_paths_SAS {

	// public static final double ALPHA = 15;
	// public static final double BETA = 1.2;

	public static Comparator<Node> NodeNameComparator = new Comparator<Node>() {
		public int compare(Node node1, Node node2) {
			// ascending order
			return Integer.valueOf(node1.getName()).compareTo(
					Integer.valueOf(node2.getName()));
		}
	};

	public static void main(String[] args) throws IOException {

		Node source = null;
		String sourceString = null;
		String sasKFactFileAddress = "./results/SASKFact.txt";
		String sasDemandFileAddress = "./results/SASDemand.txt";
		String sasPathDemandFileAddress = "./results/SASPathDemand.txt";
		String humanFileAddress = "./results/HumanPathLink.txt";
		
		
		try {

			Double alpha = Double.parseDouble(args[2]);
			Double beta = Double.parseDouble(args[3]);

			File sasDemandFile = new File(sasDemandFileAddress);
			PrintWriter sasDemandPrintWriter = new PrintWriter(new FileWriter(sasDemandFile,
					false));
			
			File sasPathDemandFile = new File(sasPathDemandFileAddress);
			PrintWriter sasPathDemandPrintWriter = new PrintWriter(new FileWriter(sasPathDemandFile,
					false));
			
			File sasKFactFile = new File(sasKFactFileAddress);
			PrintWriter sasKFactPrintWriter = new PrintWriter(new FileWriter(sasKFactFile,
					false));

			
			sasKFactPrintWriter
			.println("Path_ID\tDemand_ID\tOrigin\t\tDestination\tP_Origin\tP_Destination\tkfact");
			
			sasPathDemandPrintWriter
					.println("Path_ID\tDemand_ID\tOrigin\tDestination");

			sasDemandPrintWriter
			.println("Demand_ID\tP_Origin\tP_Destination");

			
			File readableFile = new File(humanFileAddress);
			PrintWriter readablePrintWrite = new PrintWriter(new FileWriter(
					readableFile, false));

			// // For every source and destination

			File file;
			BufferedReader fileReader;

			System.out.println("Reading: " + args[1]);
			file = new File(args[1]);
			fileReader = new BufferedReader(new FileReader(file));
			String line;
			sourceString = null;
			long pathId = 0;
			long demandId=0;
			while ((line = fileReader.readLine()) != null) {
				sourceString = null;
				String[] params = line.split("\\s+");
				if (params.length > 1) {
					for (String destinationString : params) {
						if (sourceString == null) {
							sourceString = destinationString;
							System.out.println("From: " + sourceString + " To:" ); 
						} else {
							demandId++;
							System.out.println("\t" + destinationString);
							sasDemandPrintWriter.println(demandId+"\t\t"+sourceString+"\t\t"+destinationString);
							// Load Dijkstra
							LinkState linkState = new LinkState();
							linkState.loadGraph(args[0]);
							linkState.initialize();
							source = linkState.nodesMap.get(sourceString);
							Node destination = linkState.nodesMap
									.get(destinationString);
							linkState.populateLeastCostPaths(source);

							int shortestPathHops = (linkState.leastCostPathTo(
									linkState.nodesMap.get(destinationString))
									.size() - 1);
							int maxHop = (int) Math.round(shortestPathHops
									+ (alpha * Math.log(shortestPathHops + 1))
									/ shortestPathHops);

							double minCost = destination.getMinCost();
							double minCostThreshold = minCost
									+ (beta * Math.log(minCost + 1));

							readablePrintWrite.println("ALPHA: " + alpha);
							readablePrintWrite.println("BETA: " + beta);

							printResults(source, destination, linkState,
									minCostThreshold, shortestPathHops, maxHop,demandId,
									readablePrintWrite);

							AllPaths allPaths = new AllPaths();
							allPaths.loadGraph(args[0]);

							ArrayList<ArrayList<Node>> pathList = allPaths
									.getAllPathsList(
											new ArrayList<Node>(),
											allPaths.nodesMap.get(sourceString),
											allPaths.nodesMap
													.get(destinationString),
											maxHop);

							Node previous = null;
							long boundPathCount = 0;

							for (ArrayList<Node> path : pathList) {
								previous = null;
								if (allPaths.getCost(path) < minCostThreshold) {
									boundPathCount++;
									pathId++;
									sasPathDemandPrintWriter.println(pathId+"\t"+demandId+"\t\t"+sourceString+"\t\t"+destinationString);
									for (Node node : path) {
										readablePrintWrite.print(">" + node);
										if (previous != null)
											sasKFactPrintWriter
													.println(pathId
															+ "\t"
															+demandId
															+ "\t\t"
															+ previous
															+ "\t\t"
															+ node
															+ "\t\t"
															+ allPaths.nodesMap
																	.get(sourceString)
															+ "\t\t"
															+ allPaths.nodesMap
																	.get(destinationString)
															+ "\t\t1");
										previous = node;
									}
									readablePrintWrite.println("  	cost: "
											+ allPaths.getCost(path) + " path ID: " + pathId );
								}
								sasKFactPrintWriter.flush();
								readablePrintWrite.flush();
								sasDemandPrintWriter.flush();
								sasPathDemandPrintWriter.flush();
							}

							readablePrintWrite.println("\nAll Path Count: "
									+ pathList.size());
							readablePrintWrite.println("Bound Path Count: "
									+ boundPathCount);
							readablePrintWrite
									.println("---------------------------------------------------------------------------------------------------------------------\n");

						}

					}
				}
			}
			fileReader.close();
			sasKFactPrintWriter.close();
			readablePrintWrite.close();
			sasDemandPrintWriter.close();
			sasPathDemandPrintWriter.close();
			System.out.println("Program finished successfully!");
			System.out.println("See:");
			System.out.println("\t"+humanFileAddress);
			System.out.println("\t"+sasKFactFileAddress);
			System.out.println("\t"+sasPathDemandFileAddress);
			System.out.println("\t"+sasDemandFileAddress);
		} catch (Exception e) {
			System.out.println("Error Occured: " + e.getMessage());
			System.err
					.println("USAGE:\n java all_paths_SAS <graph file name> <path file name> <ALPHA> <BETA>\n Example:\njava all_paths_SAS ./network/node1.txt ./network/paths.txt 10 1.5");
			e.printStackTrace();
			e.printStackTrace();
		}

		try {
		    Thread.sleep(8000);
		} catch(InterruptedException ex) {
		    Thread.currentThread().interrupt();
		}
	}

	public static void printResults(Node source, Node destination,
			LinkState linkState, double minCostThreshold, int shortestPathHops,
			int maxHop, long demandId, PrintWriter printWriter) {

		printWriter.println("Source: " + source);
		printWriter.println("Destination: " + destination);
		printWriter.println("Demand ID: " + demandId);
		printWriter.println("Least Cost: " + destination.getMinCost());
		printWriter.println("Least Cost Threshold: " + minCostThreshold);
		printWriter.println("Shortest path Hops: " + shortestPathHops);
		printWriter.println("Max Path Hops: " + maxHop);
		printWriter.println("Path: " + linkState.leastCostPathTo(destination));

		printWriter.println("-------------------------------");
	}

	public static void main_(String[] args) {
		// ////////////
		try {
			File file;
			BufferedReader fileReader;

			file = new File("./results/PathOD.txt");
			fileReader = new BufferedReader(new FileReader(file));
			String line;
			String sourceString = null;
			while ((line = fileReader.readLine()) != null) {
				sourceString = null;
				String[] params = line.split("\\s+");
				if (params.length > 1) {
					for (String destinationString : params) {
						if (sourceString == null) {
							sourceString = destinationString;
							System.out.println(sourceString);
						} else {
							System.out.println("\t" + destinationString);
						}

					}
				}
			}
			fileReader.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
